package com.auxiliary;

import java.util.ArrayList;
import java.util.List;

public class SeasonAdjuster {
	
	private int MCD;
	private int size;
	private List<Double> XList;
	private List<Double> TCList;
	private List<Double> SAList;
	private List<Double> SFList;
	private List<Double> IRList;
	private List<String> xAxis ;
	
	public SeasonAdjuster(TimeSequence sequence, int frequency, int type) {
		this.size = sequence.getDataCount();
		this.xAxis = sequence.getDateList();
		this.XList = sequence.getValueList();
		
		int count = 0;
		if(frequency == 1)
			count = 12;
		else if(frequency == 2)
			count = 4;
		else
			count = 1;
		
		this.calc(count);
		this.calcMCD(count);
	}
	
	/*
	 * 通过X-12方法进行季节调整
	 * @param int
	 */
	private void calc(int count) {
		BasicCalculator bc = new BasicCalculator();
		
		//对原始序列进行2*count项移动平均，得到TC序列初始估计
		TCList = bc.M_Mul_NMoving(XList, 2, count);
		//用原序列与TC序列求出SI序列，并分割成count个子序列
		List<List<Double>> SI = spitSIList(bc.listPSME(XList, TCList, 2), count);
		
		//对SI各个子序列进行3*3项移动平均
		for(int i = 0; i < SI.size(); i++)
			SI.set(i, bc.M_Mul_NMoving(SI.get(i), 3, 3));
		
		//合并SI序列，得到SA序列的初始模糊估计SList
		List<Double> SList = comSIList(SI, count);
		//对SList进行处理，消除TC要素，得到SF的初始估计
		SFList = bc.listPSME(SList, bc.M_Mul_NMoving(SList, 2, 12), 2);
		//用原序列与SF序列求出SA序列的初始估计
		SAList = bc.listPSME(XList, SFList, 2);
		
		//运用Henderson移动平均，再次对TC进行估计
		TCList = bc.hendersonList(SAList, 13);
		
		//再次用原序列和更精确的TC序列求出SI序列，并分隔成count个子序列
		SI = spitSIList(bc.listPSME(XList, TCList, 2), count);
		
		//对SI各个子序列进行3*5项移动平均，进行更精确的估计
		for(int i = 0; i < SI.size(); i++)
			SI.set(i, bc.M_Mul_NMoving(SI.get(i), 3, 5));
		
		//合并SI序列，得到SA序列的最终估计SList
		SList = comSIList(SI, count);
		//对SList进行处理，消除TC要素，得到SF的最终估计
		SFList = bc.listPSME(SList, bc.M_Mul_NMoving(SList, 2, 12), 2);
		//用原序列与SF序列求出SA序列的最终估计
		SAList = bc.listPSME(XList, SFList, 2);
		
		
		double AVG_I = bc.calcAvg(bc.listPSME(SAList, TCList, 2));
		double AVG_TC = bc.calcAvg(TCList);
		//根据序列性质，对SA序列进行特定项的Henderson移动平均，得到最终的TC序列
		if(AVG_I / AVG_TC < 1)
			TCList = bc.hendersonList(SAList, 9);
		else if(AVG_I / AVG_TC < 3.5)
			TCList = bc.hendersonList(SAList, 13);
		else
			TCList = bc.hendersonList(SAList, 23);
		
		//根据SA和TC序列，求出IR序列
		IRList = bc.listPSME(SAList, TCList, 2);
	}
	
	/*
	 * 划分子序列
	 * @param List<Double> list 需要划分的原序列
	 * @param int count 划分后的子序列数
	 * @return List<List<Double>> 划分后序列
	 */
	public List<List<Double>> spitSIList(List<Double> list, int count) {
		
		List<List<Double>> spitList = new ArrayList<List<Double>>();
		
		for(int i = 0; i < list.size(); i++) {
			if(i < count)
				spitList.add(new ArrayList<Double>());
			spitList.get(i % count).add(list.get(i));
		}
		
		return spitList;
	}
	
	/*
	 * 合并序列
	 * @param List<List<Double>> spitList 需要合并的原序列
	 * @param int count 原序列含有的子序列数
	 * @return List<Double> 合并后后序列
	 */
	public List<Double> comSIList(List<List<Double>> spitList, int count) {
		
		List<Double> comList = new ArrayList<Double>();
		
		for(int i = 0; i < size; i++) {
			comList.add(spitList.get(i % count).remove(0));
		}
		
		return comList;
	}
	
	/*
	 * 计算MCD值
	 * @param List<List<Double>> spitList 需要合并的原序列
	 * @param int count 原序列含有的子序列数
	 * @return List<Double> 合并后后序列
	 */
	private void calcMCD(int count) {
		BasicCalculator bc = new BasicCalculator();
		
		List<Double> TC = new ArrayList<Double>(this.TCList);
		List<Double> IR = new ArrayList<Double>(this.IRList);
		
		for(int i = TC.size() - 1; i >= 0; i--) {
			if(i == 0) {
				TC.set(i, 0.0);
				IR.set(i, 0.0);
			}
			else {
				TC.set(i, TC.get(i) - TC.get(i - 1));
				IR.set(i, IR.get(i) - IR.get(i - 1));
			}
		}
		
		List<List<Double>> TCSpit = this.spitSIList(TC, count);
		List<List<Double>> TRSpit = this.spitSIList(IR, count);
		
		for(int i = count / 4 - 1; i < count / 2; i++) {
			double tc = bc.calcAbsAvg(TCSpit.get(i));
			double ir = bc.calcAbsAvg(TRSpit.get(i));
			
			if(ir / tc < 1) {
				MCD = i + 1;
				return;
			}
		}

		MCD = 6;
	}

	public int getMCD() {
		return MCD;
	}

	public void setMCD(int mCD) {
		MCD = mCD;
	}

	public int getSize() {
		return size;
	}

	public void setSize(int size) {
		this.size = size;
	}

	public List<Double> getXList() {
		return XList;
	}

	public void setXList(List<Double> xList) {
		XList = xList;
	}

	public List<Double> getTCList() {
		return TCList;
	}

	public void setTCList(List<Double> tCList) {
		TCList = tCList;
	}

	public List<Double> getSAList() {
		return SAList;
	}

	public void setSAList(List<Double> sAList) {
		SAList = sAList;
	}

	public List<Double> getSFList() {
		return SFList;
	}

	public void setSFList(List<Double> sFList) {
		SFList = sFList;
	}

	public List<Double> getIRList() {
		return IRList;
	}

	public void setIRList(List<Double> iRList) {
		IRList = iRList;
	}

	public List<String> getxAxis() {
		return xAxis;
	}

	public void setxAxis(List<String> xAxis) {
		this.xAxis = xAxis;
	}
}
